
#include "common.h"

//STATE_UNIT_DEVICE_LIST DiskState = {0};
//PSTATE_UNIT_DEVICE_LIST pDiskState = &DiskState;

UCHAR CommonOpInquiry(    __in pHW_HBA_EXT DevExt,
                          __in pHW_LU_EXTENSION LuExt,
                          __in PSCSI_REQUEST_BLOCK Srb ){


    PINQUIRYDATA          pInqData = pSrb->DataBuffer;// Point to Inquiry buffer.
    UCHAR                 deviceType,
                          status = SRB_STATUS_SUCCESS;
    PCDB                  pCdb;
    pHW_LU_EXTENSION_MPIO pLUMPIOExt;
#if defined(_AMD64_)
    KLOCK_QUEUE_HANDLE    LockHandle;
#else
    KIRQL                 SaveIrql;
#endif

    RtlZeroMemory((PUCHAR)pSrb->DataBuffer, pSrb->DataTransferLength);

    deviceType = MpGetDeviceType(pHBAExt, pSrb->PathId, pSrb->TargetId, pSrb->Lun);

    if (DEVICE_NOT_FOUND==deviceType) {
       pSrb->DataTransferLength = 0;
       status = SRB_STATUS_INVALID_LUN;

       goto done;
    }

    pCdb = (PCDB)pSrb->Cdb;

    if (1==pCdb->CDB6INQUIRY3.EnableVitalProductData) {
        DoStorageTraceEtw(DbgLvlLoud, MpDemoDebugInfo, "Received VPD request for page 0x%x\n",
                          pCdb->CDB6INQUIRY.PageCode);

        //status = ScsiOpVPD(pHBAExt, pLUExt, pSrb);



        status = CommonOpVPD(pHBAExt, pLUExt, pSrb);

        goto done;
    }

    __debugbreak();

/*    pInqData->DeviceType = deviceType;
    pInqData->RemovableMedia = FALSE;
    pInqData->CommandQueue = TRUE;

    RtlMoveMemory(pInqData->VendorId, pHBAExt->VendorId, 8);
    RtlMoveMemory(pInqData->ProductId, pHBAExt->ProductId, 16);
    RtlMoveMemory(pInqData->ProductRevisionLevel, pHBAExt->ProductRevision, 4);

    if (deviceType!=DISK_DEVICE) {                    // Shouldn't happen.
        goto done;
    }

    // Check if the device has already been seen.

    if (GET_FLAG(pLUExt->LUFlags, LU_DEVICE_INITIALIZED)) {
        // This is an existing device.

        goto done;
    }

    //
    // A new LUN.
    //

    pLUExt->DeviceType = deviceType;
    pLUExt->TargetId   = pSrb->TargetId;
    pLUExt->Lun        = pSrb->Lun;

    if (pHBAExt->pMPDrvObj->MPRegInfo.bCombineVirtDisks) { // MPIO support?
        // Find the matching MPIO LUN descriptor or get a new one.

        pLUMPIOExt = ScsiGetMPIOExt(pHBAExt, pLUExt, pSrb);

        if (!pLUMPIOExt) {                            // A problem?
            pSrb->DataTransferLength = 0;
            status = SRB_STATUS_ERROR;

            goto done;
        }

        SET_FLAG(pLUExt->LUFlags, LU_MPIO_MAPPED);
    }
    else {                                            // No MPIO support.
        ScsiAllocDiskBuf(pHBAExt, &pLUExt->pDiskBuf, &pLUExt->MaxBlocks);

        if (!pLUExt->pDiskBuf) {
            DoStorageTraceEtw(DbgLvlErr, MpDemoDebugInfo, "Disk memory allocation failed!\n");

            pSrb->DataTransferLength = 0;
            status = SRB_STATUS_ERROR;

            goto done;
        }
    }

    SET_FLAG(pLUExt->LUFlags, LU_DEVICE_INITIALIZED);

#if defined(_AMD64_)
    KeAcquireInStackQueuedSpinLock(                   // Serialize the linked list of LUN extensions.
                                   &pHBAExt->LUListLock, &LockHandle);
#else
    KeAcquireSpinLock(&pHBAExt->LUListLock, &SaveIrql);
#endif

    InsertTailList(&pHBAExt->LUList, &pLUExt->List);  // Add LUN extension to list in HBA extension.

#if defined(_AMD64_)
    KeReleaseInStackQueuedSpinLock(&LockHandle);
#else
    KeReleaseSpinLock(&pHBAExt->LUListLock, SaveIrql);
#endif
*/
    DoStorageTraceEtw(DbgLvlInfo, MpDemoDebugInfo, "New device created. %d:%d:%d\n", pSrb->PathId, pSrb->TargetId, pSrb->Lun);

done:
    return status;

}

/**************************************************************************************************/
/*                                                                                                */
/**************************************************************************************************/
UCHAR
CommonOpVPD(
          __in pHW_HBA_EXT          pHBAExt,          // Adapter device-object extension from StorPort.
          __in pHW_LU_EXTENSION     pLUExt,           // LUN device-object extension from StorPort.
          __in PSCSI_REQUEST_BLOCK  pSrb
         )
{
    UCHAR                  status;
    ULONG                  len;
    struct _CDB6INQUIRY3 * pVpdInquiry = (struct _CDB6INQUIRY3 *)&pSrb->Cdb;;

    ASSERT(pLUExt != NULL);
    ASSERT(pSrb->DataTransferLength>0);

    if (0==pSrb->DataTransferLength) {
        DoStorageTraceEtw(DbgLvlErr, MpDemoDebugInfo, "pSrb->DataTransferLength = 0\n");

        return SRB_STATUS_DATA_OVERRUN;
      }


    if ( !GetDiskParameters (
                         pHBAExt->pMPDrvObj->MPRegInfo
                        ))
        return SRB_STATUS_ERROR;


    RtlZeroMemory((PUCHAR)pSrb->DataBuffer,           // Clear output buffer.
                  pSrb->DataTransferLength);

    if (VPD_SUPPORTED_PAGES==pVpdInquiry->PageCode) { // Inquiry for supported pages? //KAS
      PVPD_SUPPORTED_PAGES_PAGE pSupportedPages;

      len = sizeof(VPD_SUPPORTED_PAGES_PAGE) + 8;

      if (pSrb->DataTransferLength < len) {
        return SRB_STATUS_DATA_OVERRUN;
      }

      pSupportedPages = pSrb->DataBuffer;             // Point to output buffer.

      pSupportedPages->DeviceType = DISK_DEVICE;
      pSupportedPages->DeviceTypeQualifier = 0;
      pSupportedPages->PageCode = VPD_SERIAL_NUMBER;
      pSupportedPages->PageLength = 8;                // Enough space for 4 VPD values.
      pSupportedPages->SupportedPageList[0] =         // Show page 0x80 supported.
        VPD_SERIAL_NUMBER;
      pSupportedPages->SupportedPageList[1] =         // Show page 0x83 supported.
        VPD_DEVICE_IDENTIFIERS;

      status = SRB_STATUS_SUCCESS;
    }
    else
    if (VPD_SERIAL_NUMBER==pVpdInquiry->PageCode) {   // Inquiry for serial number?
      PVPD_SERIAL_NUMBER_PAGE pVpd;

      len = sizeof(VPD_SERIAL_NUMBER_PAGE) + 8 + 32;
      if (pSrb->DataTransferLength < len) {
        return SRB_STATUS_DATA_OVERRUN;
      }

      pVpd = pSrb->DataBuffer;                        // Point to output buffer.

      pVpd->DeviceType = DISK_DEVICE;
      pVpd->DeviceTypeQualifier = 0;
      pVpd->PageCode = VPD_SERIAL_NUMBER;
      pVpd->PageLength = 8 + 32;

      if (pHBAExt->pMPDrvObj->MPRegInfo.bCombineVirtDisks) { // MPIO support?
          /* Generate a constant serial number. */
//        sprintf((char *)pVpd->SerialNumber, "000%02d%03d0123456789abcdefghijABCDEFGHIJxx\n",
//                pLUExt->TargetId, pLUExt->Lun);
      }
      else {
          /* Generate a changing serial number. */
//        sprintf((char *)pVpd->SerialNumber, "%03d%02d%03d0123456789abcdefghijABCDEFGHIJxx\n",
//                pHBAExt->pMPDrvObj->DrvInfoNbrMPHBAObj, pLUExt->TargetId, pLUExt->Lun);
      }

      DoStorageTraceEtw(DbgLvlLoud, MpDemoDebugInfo,
                        "ScsiOpVPD:  VPD Page: %d Serial No.: %s", pVpd->PageCode, (const char *)pVpd->SerialNumber);

      status = SRB_STATUS_SUCCESS;
    }
    else
    if (VPD_DEVICE_IDENTIFIERS==pVpdInquiry->PageCode) { // Inquiry for device ids?
        PVPD_IDENTIFICATION_PAGE pVpid;
        PVPD_IDENTIFICATION_DESCRIPTOR pVpidDesc;

        #define VPIDNameSize 32
        #define VPIDName     "PSSLUNxxx"

        len = sizeof(VPD_IDENTIFICATION_PAGE) + sizeof(VPD_IDENTIFICATION_DESCRIPTOR) + VPIDNameSize;

        if (pSrb->DataTransferLength < len) {
          return SRB_STATUS_DATA_OVERRUN;
        }

        pVpid = pSrb->DataBuffer;                     // Point to output buffer.

        pVpid->PageCode = VPD_DEVICE_IDENTIFIERS;

        pVpidDesc =                                   // Point to first (and only) descriptor.
            (PVPD_IDENTIFICATION_DESCRIPTOR)pVpid->Descriptors;

        pVpidDesc->CodeSet = VpdCodeSetAscii;         // Identifier contains ASCII.
        pVpidDesc->IdentifierType =                   //
            VpdIdentifierTypeFCPHName;

        if (pHBAExt->pMPDrvObj->MPRegInfo.bCombineVirtDisks) { // MPIO support?
            /* Generate a constant serial number. */
            sprintf((char *)pVpidDesc->Identifier, "000%02d%03d0123456789abcdefghij\n",
                    pLUExt->TargetId, pLUExt->Lun);
        }
        else {
            /* Generate a changing serial number. */
            sprintf((char *)pVpidDesc->Identifier, "%03d%02d%03d0123456789abcdefghij\n",
                    pHBAExt->pMPDrvObj->DrvInfoNbrMPHBAObj, pLUExt->TargetId, pLUExt->Lun);
        }

        pVpidDesc->IdentifierLength =                 // Size of Identifier.
            (UCHAR)strlen((const char *)pVpidDesc->Identifier) - 1;
        pVpid->PageLength =                           // Show length of remainder.
            (UCHAR)(FIELD_OFFSET(VPD_IDENTIFICATION_PAGE, Descriptors) +
                    FIELD_OFFSET(VPD_IDENTIFICATION_DESCRIPTOR, Identifier) +
                    pVpidDesc->IdentifierLength);

        DoStorageTraceEtw(DbgLvlLoud, MpDemoDebugInfo,
                          "ScsiOpVPD:  VPD Page 0x83");

        status = SRB_STATUS_SUCCESS;
    }
    else {
      status = SRB_STATUS_INVALID_REQUEST;
      len = 0;
    }

    pSrb->DataTransferLength = len;

    return status;
}                                                     // End ScsiOpVPD().

VOID
GetDiskParameters(
                     __in pMP_REG_INFO    pRegInfo
                    )
/*++

Routine Description:

    This routine is called from DriverEntry to get parameters from the registry.  If the registry query
    fails, default values are used.

Return Value:

    None

--*/
{
    MP_REG_INFO defRegInfo;

    // Set default values.

    defRegInfo.BreakOnEntry       = DEFAULT_BREAK_ON_ENTRY;
    defRegInfo.DebugLevel         = DEFAULT_DEBUG_LEVEL;
    defRegInfo.InitiatorID        = DEFAULT_INITIATOR_ID;
    defRegInfo.PhysicalDiskSize   = DEFAULT_PHYSICAL_DISK_SIZE;
    defRegInfo.VirtualDiskSize    = DEFAULT_VIRTUAL_DISK_SIZE;
    defRegInfo.NbrVirtDisks       = DEFAULT_NbrVirtDisks;
    defRegInfo.NbrLUNsperHBA      = DEFAULT_NbrLUNsperHBA;
    defRegInfo.bCombineVirtDisks  = DEFAULT_bCombineVirtDisks;

    RtlInitUnicodeString(&defRegInfo.VendorId, VENDOR_ID);
    RtlInitUnicodeString(&defRegInfo.ProductId, PRODUCT_ID);
    RtlInitUnicodeString(&defRegInfo.ProductRevision, PRODUCT_REV);

    // The initialization of lclRtlQueryRegTbl is put into a subordinate block so that the initialized Buffer members of Unicode strings
    // in defRegInfo will be used.

    {
        NTSTATUS                 status;





        if (!NT_SUCCESS(status)) {                    // A problem?
            pRegInfo->BreakOnEntry      = defRegInfo.BreakOnEntry;
            pRegInfo->DebugLevel        = defRegInfo.DebugLevel;
            pRegInfo->InitiatorID       = defRegInfo.InitiatorID;
            pRegInfo->PhysicalDiskSize  = defRegInfo.PhysicalDiskSize;
            pRegInfo->VirtualDiskSize   = defRegInfo.VirtualDiskSize;
            RtlCopyUnicodeString(&pRegInfo->VendorId,  &defRegInfo.VendorId);
            RtlCopyUnicodeString(&pRegInfo->ProductId, &defRegInfo.ProductId);
            RtlCopyUnicodeString(&pRegInfo->ProductRevision, &defRegInfo.ProductRevision);
            pRegInfo->NbrVirtDisks      = defRegInfo.NbrVirtDisks;
            pRegInfo->NbrLUNsperHBA     = defRegInfo.NbrLUNsperHBA;
            pRegInfo->bCombineVirtDisks = defRegInfo.bCombineVirtDisks;
        }
    }
}




